/****************************************************************************
                Университет:    Санкт-Петербургский Политехнический Университет
                Кафедра:        Компьютерные системы и программные технологии
                Аспирант:       Быков Илья Иванович
                Программа:      Расчет коэффициентов распределения
                Модуль:         mainwindow.cpp
                Назначение:
****************************************************************************/

#include <QDebug>
#include <QUndoGroup>
#include <QUndoStack>
#include <QPainter>
#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>
#include <QToolButton>
#include <QGraphicsScene>
#include <QDomDocument>

#include "document.h"
#include "mainwindow.h"
#include "node.h"
#include "removenodecommand.h"
#include "removeedgecommand.h"
#include "setnodecolorcommand.h"
#include "dialog.h"
#include "dialog_settings.h"
#include "modulestabdialog.h"

MainWindow *MainWindow::g_mainWindow = 0;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , m_editingMode(Select)
{
    ui->setupUi(this);

    g_mainWindow = this;

    QWidget *w = ui->documentTabs->widget(0);
    ui->documentTabs->removeTab(0);
    delete w;

    // Кнопка запуска с меню
    QMenu *menu = new QMenu(this);
    moduleList = modules();
    foreach(ModuleManifest* Module, moduleList)
    {
        menu->addAction(Module->Name());
    }
    ui->action_Run->setMenu(menu);
    connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(run(QAction*)));

    // Связь сигналов со слотами
    connect(ui->actionOpen, SIGNAL(triggered()), SLOT(openDocument()));
    connect(ui->actionClose, SIGNAL(triggered()), SLOT(closeDocument()));
    connect(ui->actionNew, SIGNAL(triggered()), SLOT(newDocument()));
    connect(ui->actionSave, SIGNAL(triggered()), SLOT(saveDocument()));
    connect(ui->actionExit, SIGNAL(triggered()), SLOT(close()));
    connect(ui->actionRed, SIGNAL(triggered()), SLOT(setNodeColor()));
    connect(ui->actionGreen, SIGNAL(triggered()), SLOT(setNodeColor()));
    connect(ui->actionBlue, SIGNAL(triggered()), SLOT(setNodeColor()));
    connect(ui->actionRemoveShape, SIGNAL(triggered()), SLOT(removeItem()));
    connect(ui->actionAbout, SIGNAL(triggered()), SLOT(about()));

    connect(ui->undoLimit, SIGNAL(valueChanged(int)), SLOT(updateActions()));
    connect(ui->documentTabs, SIGNAL(currentChanged(int)), SLOT(updateActions()));

    // Привязка к горящим клавишам
    ui->actionOpen->setShortcut(QString("Ctrl+O"));
    ui->actionClose->setShortcut(QString("Ctrl+W"));
    ui->actionNew->setShortcut(QString("Ctrl+N"));
    ui->actionSave->setShortcut(QString("Ctrl+S"));
    ui->actionExit->setShortcut(QString("Ctrl+Q"));
    ui->actionRemoveShape->setShortcut(QString("Del"));
    ui->actionRed->setShortcut(QString("Alt+R"));
    ui->actionGreen->setShortcut(QString("Alt+G"));
    ui->actionBlue->setShortcut(QString("Alt+B"));

    m_undoGroup = new QUndoGroup(this);
    ui->undoView->setGroup(m_undoGroup);
    ui->undoView->setCleanIcon(QIcon(":/icons/ok.png"));

    QAction *undoAction = m_undoGroup->createUndoAction(this);
    QAction *redoAction = m_undoGroup->createRedoAction(this);
    undoAction->setIcon(QIcon(":/icons/undo.png"));
    redoAction->setIcon(QIcon(":/icons/redo.png"));
    ui->menuShape->insertAction(ui->menuShape->actions().at(0), undoAction);
    ui->menuShape->insertAction(undoAction, redoAction);

    ui->toolBar_file->addAction(undoAction);
    ui->toolBar_file->addAction(redoAction);

    // В окне истории заголовок пустого окна
    ui->undoView->setEmptyLabel("Пусто");

    newDocument();
    updateActions();
}

void MainWindow::updateActions()
{
    Document *doc = currentDocument();

    if (!doc) { // Нет табов
        m_undoGroup->setActiveStack(0);
        ui->actionAddNode->setChecked(false);
        ui->actionAddEdge->setChecked(false);
        ui->actionRed->setEnabled(false);
        ui->actionGreen->setEnabled(false);
        ui->actionBlue->setEnabled(false);
        setEnabledCharacters(false);
        return;
    }

    QGraphicsScene *scene = doc->scene();
    m_undoGroup->setActiveStack(doc->undoStack());

    ui->actionClose->setEnabled(true);
    ui->actionSave->setEnabled(!doc->undoStack()->isClean());
    ui->undoLimit->setEnabled(doc->undoStack()->count() == 0);
    
    ui->actionAddNode->setChecked(m_editingMode == MainWindow::AddNode ? true : false);
    ui->actionAddEdge->setChecked(m_editingMode == MainWindow::AddEdge ? true : false);

    QList<QGraphicsItem*> itemList = scene->selectedItems();
    QList<Node*> nodeList = doc->selectedNodes();

    if (nodeList.isEmpty()) {
        ui->actionRed->setEnabled(false);
        ui->actionGreen->setEnabled(false);
        ui->actionBlue->setEnabled(false);
    } 
    else if (nodeList.size() == 1) {
        ui->actionRed->setEnabled(nodeList[0]->color() != Qt::red);
        ui->actionGreen->setEnabled(nodeList[0]->color() != Qt::green);
        ui->actionBlue->setEnabled(nodeList[0]->color() != Qt::blue);
    }
    else {
        ui->actionRed->setEnabled(true);
        ui->actionGreen->setEnabled(true);
        ui->actionBlue->setEnabled(true);
    }

    ui->actionRemoveShape->setEnabled(!itemList.isEmpty());
    
    if (doc != 0) {
        int index = ui->documentTabs->indexOf(doc);
        Q_ASSERT(index != -1);
        static const QIcon unsavedIcon(":/icons/filesave.png");
        ui->documentTabs->setTabIcon(index, doc->undoStack()->isClean() ? QIcon() : unsavedIcon);

        if (doc->undoStack()->count() == 0)
            doc->undoStack()->setUndoLimit(ui->undoLimit->value());
    }

    doc->updateCharacters();
}

// Установить активными\неактивными опарации с матрицами
void MainWindow::setEnabledCharacters(bool b)
{
    ui->menuCharacters->setEnabled(b);
    ui->actionMatrixCircuit->setEnabled(b);
    ui->actionMatrixPaths->setEnabled(b);
    ui->actionMatrixBranches->setEnabled(b);
    ui->actionCommentMatrix->setEnabled(b);
    ui->actionFullReport->setEnabled(b);
    ui->action_node_settings->setEnabled(b);
    ui->action_edge_settings->setEnabled(b);
}

// Открытие файла
void MainWindow::openDocument()
{
    QString fileName = QFileDialog::getOpenFileName(this, "Открытие файла",QString(),
                                                    "РКР-файл (*.eec)",0,0);
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        QMessageBox::warning(this,
                             "Ошибка открытия файла",
                             QString("Файл имеет другой формат!\n%1").arg(fileName));
        return;
    }

    if (currentDocument()->nodes().isEmpty()) {
        removeDocument(currentDocument());
    }

    Document *doc = new Document();
    doc->setFileName(fileName);
    addDocument(doc);

    QTextStream stream(&file);
    if (!doc->load(stream)) {
        QMessageBox::warning(this,
                             "Ошибка открытия файла",
                             QString("Файл имеет другой формат!\n%1").arg(fileName));
        delete doc;
        return;
    }

    QMainWindow::statusBar()->showMessage("Файл "+
                                          QFileInfo(doc->fileName()).fileName()+
                                          " открыт",5000);
}



// Заголовок рабочей области
QString MainWindow::fixedWindowTitle(const Document *doc) const
{
    QString title = doc->fileName();

    if (title.isEmpty())
        title = "Безымянный ";
    else
        title = QFileInfo(title).fileName();

    QString result;

    for (int i = 0; ; ++i) {
        result = title;
        if (i > 0)
            result += QString::number(i);

        bool unique = true;
        for (int j = 0; j < ui->documentTabs->count(); ++j) {
            const QWidget *widget = ui->documentTabs->widget(j);
            if (widget == doc)
                continue;
            if (result == ui->documentTabs->tabText(j)) {
                unique = false;
                break;
            }
        }

        if (unique)
            break;
    }

    return result;
}

// Используется в openDocument() и newDocument()
void MainWindow::addDocument(Document *doc)
{
    if (ui->documentTabs->indexOf(doc) != -1)
        return;
    m_undoGroup->addStack(doc->undoStack());

    ui->documentTabs->addTab(doc, fixedWindowTitle(doc));
    connect(doc->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
    connect(doc->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));

    // Устанавливаем новый документ как рабочий
    setCurrentDocument(doc);
}

// Устанавливаем документ как рабочий.  Используется в addDocument
void MainWindow::setCurrentDocument(Document *doc)
{
    ui->documentTabs->setCurrentWidget(doc);
}


Document *MainWindow::currentDocument() const
{
    return qobject_cast<Document*>(ui->documentTabs->currentWidget());
}

MainWindow::EditingMode MainWindow::editingMode() const
{
    return m_editingMode;
}


MainWindow *MainWindow::instance()
{
    return g_mainWindow;
}

// Закрытие файла (используетсяв closedocument)
void MainWindow::removeDocument(Document *doc)
{
    int index = ui->documentTabs->indexOf(doc);
    if (index == -1)
        return;

    ui->documentTabs->removeTab(index);
    m_undoGroup->removeStack(doc->undoStack());
    disconnect(doc->undoStack(), SIGNAL(indexChanged(int)), this, SLOT(updateActions()));
    disconnect(doc->undoStack(), SIGNAL(cleanChanged(bool)), this, SLOT(updateActions()));

    updateActions();
}

// Сохранение файла
void MainWindow::saveDocument()
{
    Document *doc = currentDocument();
    if (doc == 0)
        return;

    for (;;) {
        QString fileName = doc->fileName();

        if (fileName.isEmpty())
            fileName = QFileDialog::getSaveFileName(this,"Сохранение файла",QString(),
                                                    "РКР-файл (*.eec)",0,0);
        if (fileName.isEmpty())
            break;

        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly))
        {
            QMessageBox::warning(this,
                                 "Ошибка открытия файла",
                                 QString("Файл имеет другой формат!\n%1").arg(fileName));
            doc->setFileName(QString());
        }
        else
        {
            QTextStream stream(&file);
            doc->save(stream);
            doc->setFileName(fileName);

            int index = ui->documentTabs->indexOf(doc);
            Q_ASSERT(index != -1);
            ui->documentTabs->setTabText(index, fixedWindowTitle(doc));
            QMainWindow::statusBar()->showMessage("Файл сохранен",5000);
            break;
        }
    }
}

// Закрытие файла
void MainWindow::closeDocument()
{
    Document *doc = currentDocument();
    if (doc == 0)
        return;

    if (!doc->undoStack()->isClean()) {
        int button
            = QMessageBox::warning(this,
                            "Несохраненные изменения",
                            "Сохранить изменения?",
                            QMessageBox::Yes, QMessageBox::No);
        if (button == QMessageBox::Yes){
            saveDocument();
            QMainWindow::statusBar()->showMessage("Файл сохранен и закрыт",5000);
        } 
        else {
            QMainWindow::statusBar()->showMessage("Файл был закрыт без сохранения",5000);
        }
    }

    removeDocument(doc);
        
    if (ui->documentTabs->count() == 0) {
        newDocument();
        updateActions();
    }

    delete doc;
}

void MainWindow::newDocument()
{
    addDocument(new Document());
}

void MainWindow::EdgeDataRead(const QList<int> &state, const QList<double> &resist_R, const QList<double> &resist_X,
                              const QList<double> &power_a, const QList<double> &power_r,
                              const QList<double> &otr_pow_a, const QList<double> &pol_pow_a)
{
    foreach (Edge *edge, currentDocument()->edges())
    {
        int number = edge->number();
        edge->setState(state[number-1]);
        edge->setResist(resist_R[number-1], resist_X[number-1]);
        edge->setPower(power_a[number-1], power_r[number-1]);
        edge->setLimitPower(otr_pow_a[number-1], pol_pow_a[number-1]);
    }
}

void MainWindow::NodeDataRead(const QList<int> &state, const QList<double> &voltage,
                              const QList<double> &a_p, const QList<double> &r_p,
                              const QList<double>&max_Pa, const QList<double>&min_Pa)
{
    foreach (Node *node, currentDocument()->nodes())
    {
        int number = node->number();
        node->setstate(state[number-1]);
        node->setVoltage(voltage[number-1]);
        node->setPower(a_p[number-1], r_p[number-1]);
        node->setMaxMinActivePower(max_Pa[number-1], min_Pa[number-1]);
        node->redraw();
    }
}


void MainWindow::EdgeDataWrite(QList<double> &resist_R, QList<double> &resist_X)
{
    int i = 0;
    foreach (Edge *edge, currentDocument()->edges())
    {
        edge->getResist(resist_R[i], resist_X[i]);
        i++;
    }
}

void MainWindow::removeItem()
{
    Document *doc = currentDocument();
    if (doc == 0)
        return;

    QList<Node*> nodeList = doc->selectedNodes();
    if (!nodeList.isEmpty()) {
        doc->undoStack()->push(new RemoveNodeCommand(doc, nodeList));
    }

    QList<Edge*> edgeList = doc->selectedEdges();
    if (!edgeList.isEmpty()) {
        doc->undoStack()->push(new RemoveEdgeCommand(doc, edgeList));
    }
}


// Установить цвет выделенного узла\узлов
void MainWindow::setNodeColor()
{
    Document *doc = currentDocument();
    if (doc == 0)
        return;

    QList<QGraphicsItem*> itemList = doc->scene()->selectedItems();
    QList<Node*> nodeList;
    foreach (QGraphicsItem *item, itemList) {
        if (item->type() == Node::Type) {
            nodeList << (Node*)item;
        }
    }

    QColor color;
    if (sender() == ui->actionRed)
        color = Qt::red;
    else if (sender() == ui->actionGreen)
        color = Qt::green;
    else if (sender() == ui->actionBlue)
        color = Qt::blue;
    else
        return;

    doc->undoStack()->push(new SetNodeColorCommand(doc, nodeList, color));
    QMainWindow::statusBar()->showMessage("Изменен цвет объекта",5000);
}

void MainWindow::about()
{
    QMessageBox::about(this,  "Справка",
                       "Программа формирования полной матрицы контуров, матрицы путей и расчета\n"
                       "коэффициентов распределения методом последовательных приближений.");
}

void MainWindow::on_actionAddNode_triggered(bool checked)
{
    if (checked) {
        m_editingMode = MainWindow::AddNode;
        currentDocument()->scene()->clearSelection();
    } 
    else {
        m_editingMode = MainWindow::Select;
    }
    updateActions();
}

void MainWindow::on_actionAddEdge_triggered(bool checked)
{
    if (checked) {
        m_editingMode = MainWindow::AddEdge;
        currentDocument()->scene()->clearSelection();
    } 
    else {
        m_editingMode = MainWindow::Select;
    }
    updateActions();
}

void MainWindow::on_actionMatrixCircuit_triggered()
{
    Dialog *dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_circuit.png"));
    dlg->showMatrixCircuit(currentDocument()->nodes());
}

void MainWindow::on_actionMatrixBranches_triggered()
{
    Dialog *dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_branches.png"));
    dlg->showMatrixBranches(currentDocument()->nodes());
}

void MainWindow::on_actionMatrixPaths_triggered()
{
    Dialog *dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_paths.png"));
    dlg->showMatrixPaths(currentDocument()->nodes());
}

void MainWindow::on_actionCommentMatrix_triggered()
{
    Dialog *dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_comment.png"));
    dlg->showCommentMatrix(currentDocument()->nodes());
}

void MainWindow::on_actionFullReport_triggered()
{
    Dialog *dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_circuit.png"));
    dlg->showMatrixCircuit(currentDocument()->nodes());
    dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_branches.png"));
    dlg->showMatrixBranches(currentDocument()->nodes());
    dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_paths.png"));
    dlg->showMatrixPaths(currentDocument()->nodes());
    dlg = new Dialog(this);
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->setWindowIcon(QIcon(":/icons/matrix_comment.png"));
    dlg->showCommentMatrix(currentDocument()->nodes());
}

void MainWindow::on_action_node_settings_triggered()
{
    Dialog_settings *dlg = new Dialog_settings(this, ET_NODE);
    dlg->setFixedWidth(550);

    int row = currentDocument()->nodes().size();
    dlg->SetModelArgument(7, row);
    dlg->setWindowTitle("Настройки узлов");

    dlg->SetColHeaderData(0,"№");             // № узла
    dlg->SetColHeaderData(1,"Состояние");     // Состояние
    dlg->SetColHeaderData(2,"U, [кВ]");       // Номинальное напряжение
    dlg->SetColHeaderData(3,"Pa, [мВт]");     // Активная мощность
    dlg->SetColHeaderData(4,"Pp, [мВт]");     // Реактивная мощность
    dlg->SetColHeaderData(5,"Pa min, [мВт]");     // min Активная мощность
    dlg->SetColHeaderData(6,"Pp max, [мВт]");     // max Активная мощность

    // Устанавливаем номер узлов
    for (int i=0; i<row; i++)
        dlg->SetIndexValue(i,0,(int) i+1);


    // Устанавливаем значение сопротивлений
    int i = 0;
    foreach (Node *node, currentDocument()->nodes())
    {
        double ap, rp, u, max_Pa, min_Pa;
        node->getPower(ap, rp);
        node->getVoltage(u);
        node->getMaxMinActivePower(max_Pa, min_Pa);

        int st = node->getstate();
        if (st == 1)
            dlg->SetIndexValue(i, 1, "Включен");
        else if (st == 0)
            dlg->SetIndexValue(i, 1, "Отключен");

        dlg->SetIndexValue(i, 2, u);
        dlg->SetIndexValue(i, 3, ap);
        dlg->SetIndexValue(i, 4, rp);
        dlg->SetIndexValue(i, 5, max_Pa);
        dlg->SetIndexValue(i, 6, min_Pa);
        i++;
    }


    dlg->setWindowIcon(QIcon(":/icons/setting_node.png"));
    dlg->show();

    QObject::connect(dlg,
                     SIGNAL (NodeDataChanged( const QList<int>&, const QList<double>&, const QList<double>&, const QList<double>&, const QList<double>&, const QList<double>&)),
                     this,
                     SLOT( NodeDataRead(const QList<int>&, const QList<double>&, const QList<double>&, const QList<double>&, const QList<double>&, const QList<double>&)));
}

void MainWindow::on_action_edge_settings_triggered()
{
    Dialog_settings *dlg = new Dialog_settings(this, ET_EDGE);
    dlg->setBal(currentDocument()->bal());

    int row = currentDocument()->edges().size();
    dlg->SetModelArgument(8, row);
    dlg->setWindowTitle("Настройки ветвей");

    dlg->SetColHeaderData(0,"№ ветви");       // № ветви
    dlg->SetColHeaderData(1,"Состояние");
    dlg->SetColHeaderData(2,"R, [Ом]");       // Активные сопротивления
    dlg->SetColHeaderData(3,"X, [Ом]");       // Реактивные сопротивления
    dlg->SetColHeaderData(4,"S_a, [МВт]");    // Активная мощность
    dlg->SetColHeaderData(5,"S_q, [МВт]");    // Реактивная мощность
    dlg->SetColHeaderData(6,"S_a_отр, [МВт]");// Предельный поток для отрицательного направления
    dlg->SetColHeaderData(7,"S_a_пол, [МВт]");// Предельный поток для положительного направления


    // Устанавливаем значения
    int i = 0;
    foreach (Edge *edge, currentDocument()->edges())
    {
        // Устанавливаем номер ветвей
        dlg->SetIndexValue(edge->number()-1,0,(int) edge->number());

        // Статус
        int st = edge->getstate();
        if (st == 1)
            dlg->SetIndexValue(edge->number()-1, 1, "Включена");
        else if (st == 0)
            dlg->SetIndexValue(edge->number()-1, 1, "Отключена");

        // Сопротивления
        double r_r, r_x;
        edge->getResist(r_r, r_x);
        dlg->SetIndexValue(edge->number()-1, 2, r_r);
        dlg->SetIndexValue(edge->number()-1, 3, r_x);

        // Мощности
        double pow_a, pow_r;
        edge->getPower(pow_a, pow_r);
        dlg->SetIndexValue(edge->number()-1, 4, pow_a);
        dlg->SetIndexValue(edge->number()-1, 5, pow_r);

        double otr_pow_a, pol_pow_a;
        edge->getLimitPower(otr_pow_a, pol_pow_a);
        dlg->SetIndexValue(edge->number()-1, 6, otr_pow_a);
        dlg->SetIndexValue(edge->number()-1, 7, pol_pow_a);

        i++;
    }

    dlg->setWindowIcon(QIcon(":/icons/setting_edge.png"));
    dlg->show();

    QObject::connect(dlg,
                     SIGNAL(EdgeDataChanged(QList<int>,QList<double>,QList<double>,QList<double>,QList<double>,QList<double>,QList<double>)),
                     this,
                     SLOT(EdgeDataRead(QList<int>,QList<double>,QList<double>,QList<double>,QList<double>,QList<double>,QList<double>)));
}

// Запуск модуля по умолчанию
void MainWindow::on_action_Run_triggered()
{
    Document *doc = currentDocument();

    // Если документ пуст
    if (doc->nodes().isEmpty())
        return;

    doc->deleteTemporaryFiles();
    doc->TemporaryFile = saveDocumentInTemporaryFile();
    doc->ReportFile = TemporaryReportFile();

    QString program = "Modules/RKR/RKR.exe";
    QStringList arguments;
    arguments << doc->TemporaryFile << doc->ReportFile;

    // Запуск модулей
    QProcess *rkrProcess = new QProcess();
    connect(rkrProcess,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(analysResults(int,QProcess::ExitStatus)));
    rkrProcess->start(program, arguments);
}

// Запуск соответствующего модуля
void MainWindow::run(QAction *action)
{
    Document *doc = currentDocument();

    // Если документ пуст
    if (doc->nodes().isEmpty())
        return;

    QString algorithm_name = action->text();
    QString program;
    for (int i = 0; i < moduleList.size(); ++i)
    {
         if (moduleList.at(i)->Name() == algorithm_name)
         {
             program = moduleList.at(i)->Path();
             break;
         }
    }

    doc->deleteTemporaryFiles();
    doc->TemporaryFile = saveDocumentInTemporaryFile();
    doc->ReportFile = TemporaryReportFile();
    QStringList arguments;
    arguments << doc->TemporaryFile << doc->ReportFile;

    // Запуск модулей
    QProcess *process = new QProcess();
    connect(process,SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(analysResults(int,QProcess::ExitStatus)));
    process->start(program, arguments);
}

void MainWindow::analysResults(int exitCode, QProcess::ExitStatus exitStatus)
{
    if (exitCode != 0)
        return;

    if (exitStatus != QProcess::NormalExit)
        return;

    QDomDocument qdoc("eec");
    QFile tfile(currentDocument()->TemporaryFile);
    if (!tfile.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    if (!qdoc.setContent(&tfile))
    {
        tfile.close();
        return;
    }
    tfile.close();

    Document *doc = currentDocument();
    int edges_count = currentDocument()->edges().size();

    QVector<double> pow_a;
    pow_a.resize(edges_count);

    QVector<double> pow_r;
    pow_r.resize(edges_count);

    QDomNodeList nodeList = qdoc.elementsByTagName("node");

    for (int i = 0; i < nodeList.size(); i++)
    {
        QDomElement el = nodeList.item(i).toElement();

        QDomNodeList edgeList = el.elementsByTagName("edge");
        for (int j = 0; j < edgeList.size(); j++)
        {
            int number = edgeList.item(j).toElement().attribute("number").toInt();

            double power_a = edgeList.item(j).toElement().attribute("power_a").toDouble();
            pow_a[number-1] =  power_a;

            double power_r = edgeList.item(j).toElement().attribute("power_r").toDouble();
            pow_r[number-1] =  power_r;
        }
    }

    foreach (Edge *edge, currentDocument()->edges())
    {
        edge->setPower( pow_a.at(edge->number()-1), pow_r.at(edge->number()-1) );
    }

    doc->updateEdges();
    doc->updateCharacters();
}

void MainWindow::on_modul_settings_action_triggered()
{
    QDialog *TabDialog = new ModulesTabDialog(moduleList);
    TabDialog->show();
}


ModuleList MainWindow::modules()
{
    // Настройки модулей
    QString ModulesDirectory = "Modules";
    QDir modulesDir( ModulesDirectory );
    ModuleList moduleList;
    foreach( QString moduleDir, modulesDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot) )
    {
        ModuleManifest* Module = new ModuleManifest();
        moduleDir = modulesDir.absolutePath() + "/" + moduleDir;
        if ( Module->Load( moduleDir ) )
        {
            moduleList.append(Module);
        }
    }
    return moduleList;
}

// Сохранение документа во временный файл
QString MainWindow::saveDocumentInTemporaryFile()
{
    QString tempPath = QDir::tempPath();
    QString ct = QDateTime::currentDateTime().toString("ddMMyyhhmmsszzz");
    QString TemporaryFile = tempPath + "/" + ct + ".eec";
    QFile tfile(TemporaryFile);
    if (!tfile.open(QIODevice::WriteOnly | QIODevice::Text))
        return "";

    Document *doc = currentDocument();
    QTextStream stream(&tfile);
    doc->save(stream);
    tfile.close();

    return TemporaryFile;
}

QString MainWindow::TemporaryReportFile()
{
    QString tempPath = QDir::tempPath();
    QString ct = QDateTime::currentDateTime().toString("ddMMyyhhmmsszzz");
    QString TemporaryFile = tempPath + "/" + ct + ".txt";

    return TemporaryFile;
}

void MainWindow::on_action_open_report_triggered()
{
    QString report = currentDocument()->ReportFile;
    if (report.isEmpty())
        return;

    QUrl url = QUrl::fromLocalFile(report);
    QDesktopServices::openUrl(url);
}

void MainWindow::on_action_program_settings_triggered()
{
    QDialog *sdialog = new QDialog(this);

    // Количество отображаемых знаков
    QLabel *label = new QLabel("Количество отображаемых знаков");
    QSpinBox *spinbox = new QSpinBox();
    spinbox->setRange(0,8);
    int power_precision = currentDocument()->getPrecision();
    spinbox->setValue(power_precision);

    // Вывод сопротивления
    QCheckBox *resistance_visible_cb = new QCheckBox("Показывать сопротивления линий");
    bool resistance_status = currentDocument()->getResistanceState();
    if (resistance_status)
        resistance_visible_cb->setCheckState(Qt::Checked);
    else
        resistance_visible_cb->setCheckState(Qt::Unchecked);

    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
    connect(buttonBox, SIGNAL(accepted()), sdialog, SLOT(accept()));
    connect(buttonBox, SIGNAL(rejected()), sdialog, SLOT(reject()));

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(label);
    mainLayout->addWidget(spinbox);
    mainLayout->addWidget(resistance_visible_cb);
    mainLayout->addWidget(buttonBox);
    mainLayout->setSizeConstraint(QLayout::SetNoConstraint);

    sdialog->setLayout(mainLayout);
    sdialog->setWindowTitle("Настройки программы");

    sdialog->show();

    if (sdialog->exec() == QDialog::Accepted)
    {
        int value_spb = spinbox->value();
        bool value_chb;
        if (resistance_visible_cb->checkState()==2 || resistance_visible_cb->checkState()==1)
            value_chb = true;
        else
            value_chb = false;

        if (power_precision == value_spb && resistance_status==value_chb)
            return;

        if (power_precision != value_spb)
        {
            power_precision = value_spb;
            currentDocument()->setPrecision(power_precision);
        }

        if (resistance_status!=value_chb)
        {
            resistance_status = value_chb;
            currentDocument()->setResistanceState(resistance_status);
        }

    }
}
